package com.buct.coder.core.spider;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.buct.coder.model.Contest;
import com.buct.coder.model.Student;
import com.buct.coder.model.StudentContestLog;
import com.buct.coder.service.IContestService;
import com.buct.coder.service.IStudentContestLogService;
import com.buct.coder.service.IStudentService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * Created with IntelliJ IDEA.
 *
 * @Description:
 * @Auther: xinzi
 * @Date: 2022/08/21/14:58
 */
@Component
@Slf4j
public class CfDataSpider {

    private static final String CF_PREFIX = "https://codeforces.com/api/user.rating?handle=";

    @Resource
    private IStudentService studentService;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private IContestService contestService;
    @Resource
    private IStudentContestLogService studentContestLogService;


    @Scheduled(cron ="0 0 0 0/2 * ?")
    @Async
    public void refreshData() {
        List<Student> students = studentService.list();
        for (Student student : students) {
            String cfId = student.getCfId();
            if (StringUtils.isBlank(cfId)) {
                continue;
            }
            List<CfData> cfDataList = null;
            try {
                ResponseEntity<Response> response = restTemplate.exchange(CF_PREFIX + cfId, HttpMethod.GET,
                        new HttpEntity<>(toHeaders()), Response.class);
                cfDataList = Objects.requireNonNull(response.getBody()).getResult();
            } catch (Exception e) {
                log.warn("exception in get cf contest data", e);
            }
            if (CollectionUtils.isEmpty(cfDataList)) {
                continue;
            }
            for (CfData data : cfDataList) {
                Contest contestFromDb = contestService.getOne(
                        new LambdaQueryWrapper<Contest>().eq(Contest::getTitle, data.getContestName()).eq(Contest::getSource, "cf")
                );
                Long contestId;
                if (contestFromDb == null) {
                    Contest contest = Contest.builder()
                            .source("cf")
                            .startTime(new Date())
                            .title(data.getContestName())
                            .build();
                    contestService.save(contest);
                    contestId = contest.getId();
                } else {
                    contestId = contestFromDb.getId();
                }
                StudentContestLog contestLogFromDb = studentContestLogService.getOne(
                        new LambdaQueryWrapper<StudentContestLog>().eq(StudentContestLog::getContestId, contestId)
                                .eq(StudentContestLog::getStuId, student.getId())
                );
                if (contestLogFromDb == null) {
                    StudentContestLog contestLog = StudentContestLog.builder()
                            .stuId(student.getId())
                            .contestId(contestId)
                            .newRating(data.getNewRating())
                            .diff(data.getNewRating() >= data.getOldRating() ?
                                    "+" + (data.getNewRating() - data.getOldRating()) :
                                    "-" + (data.getOldRating() - data.getNewRating()))
                            .build();
                    studentContestLogService.save(contestLog);
                }
            }
        }
    }

    private HttpHeaders toHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        headers.set("connection", "Keep-Alive");
        return headers;
    }

    @Data
    private static class Response {
        private String status;
        private List<CfData> result;
    }

    @Data
    private static class CfData {
        private Long contestId;
        private String contestName;
        private String handle;
        private Long oldRating;
        private Long newRating;
    }

}
